package com.example.project3;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class Calculator {
    public static List<String> parseToSuffixExpression(List<String> expressionList) {
        //创建一个栈用于保存操作符
        Stack<String> opStack = new Stack<>();
        //创建一个list用于保存后缀表达式
        List<String> suffixList = new ArrayList<>();
        for(String item : expressionList){
            //得到数或操作符
            if(isOperator(item)){
                //是操作符 判断操作符栈是否为空
                if(opStack.isEmpty() || "(".equals(opStack.peek()) || priority(item) > priority(opStack.peek())){
                    //为空或者栈顶元素为左括号或者当前操作符大于栈顶操作符直接压栈
                    opStack.push(item);
                }else {
                    //否则将栈中元素出栈如队，直到遇到大于当前操作符或者遇到左括号时
                    while (!opStack.isEmpty() && !"(".equals(opStack.peek())){
                        if(priority(item) <= priority(opStack.peek())){
                            suffixList.add(opStack.pop());
                        }
                    }
                    //当前操作符压栈
                    opStack.push(item);
                }
            }else if(isNumber(item)){
                //是数字则直接入队
                suffixList.add(item);
            }else if(".".equals(item)){
                //System.out.print('a');
                suffixList.add(item);
            }else if("√".equals(item)){
                suffixList.add(item);
            }
            else {
                throw new RuntimeException("有非法字符！");
            }
        }
        //循环完毕，如果操作符栈中元素不为空，将栈中元素出栈入队
        while (!opStack.isEmpty()){
            suffixList.add(opStack.pop());
        }
        return suffixList;
    }
    /**
     * 判断字符串是否为操作符
     * @param op
     * @return
     */
    public static boolean isOperator(String op){
        return op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/");
    }

    /**
     * 判断是否为数字
     * @param num
     * @return
     */
    public static boolean isNumber(String num){
        return num.matches("^([0-9]{1,}[.][0-9]*)$") || num.matches("^([0-9]{1,})$");
    }

    /**
     * 获取操作符的优先级
     * @param op
     * @return
     */
    public static int priority(String op){
        if(op.equals("*") || op.equals("/")){
            return 1;
        }else if(op.equals("+") || op.equals("-")){
            return 0;
        }
        return -1;
    }

    /**
     * 将表达式转为list
     * @param expression
     * @return
     */
    static List<String> expressionToList(String expression) {
        int index = 0;
        List<String> list = new ArrayList<>();
        do{
            char ch = expression.charAt(index);
            if(ch!=46 && (ch <= 47 || ch >= 58)){
                //是操作符，直接添加至list中
                index ++ ;
                list.add(ch+"");
            }else{
                //是数字,判断多位数的情况
                String str = "";
                while (index < expression.length() && (expression.charAt(index) >47 && expression.charAt(index) < 58 || expression.charAt(index)==46)){
                    str += expression.charAt(index);
                    index ++;
                }
                list.add(str);
                //System.out.println(str);
            }
        }while (index < expression.length());
        return list;
    }

    /**
     * 根据后缀表达式list计算结果
     * @param list
     * @return
     */
    static double calculate(List<String> list) {
//        System.out.println(list);
        Stack<Object> stack = new Stack<>();
        for(int i=0; i<list.size(); i++){
            String item = list.get(i);
            if(item.matches("^([0-9]{1,}[.][0-9]*)$") || item.matches("^([0-9]{1,})$")){
                //是数字
                stack.push(Double.parseDouble(item));
            } else if(item.equals("√")){
                stack.push(item);
            }else {
                System.out.println(stack);
                //是操作符，取出栈顶两个元素
                double num2 = Double.parseDouble(stack.pop().toString());
                if (stack.peek().equals("√")){
                    num2 = Math.sqrt(num2);
                    stack.pop();
                }
                double num1 = Double.parseDouble(stack.pop().toString());
                if (!stack.empty()){
                    if (stack.peek().equals("√")){
                        num1 = Math.sqrt(num1);
                        stack.pop();
                    }
                }
                int precision = 0;
                String n1 = String.valueOf(num1);
                String n2 = String.valueOf(num2);
                for (int j=0;j<n1.length();j++){
                    if (n1.charAt(j)=='.'){
                        n1 = n1.substring(j+1);
                        break;
                    }
                }
                for (int j=0;j<n2.length();j++){
                    if (n2.charAt(j)=='.'){
                        n2 = n2.substring(j+1);
                        break;
                    }
                }
                precision = Math.max(n1.length(),n2.length());
                NumberFormat numberFormat=NumberFormat.getInstance();
                numberFormat.setMaximumFractionDigits(precision);
                String nu1 = numberFormat.format(num1);
                String nu2 = numberFormat.format(num2);
                num1 = Double.parseDouble(nu1);
                num2 = Double.parseDouble(nu2);
                //System.out.print(num2);
                double res = 0.000000000000000000000000;
                if(item.equals("+")){
                    res = num1 + num2;
                }else if(item.equals("-")){
                    res = num1 - num2;
//                    System.out.println(num1+" "+num2+" "+(num1-num2));
                }else if(item.equals("*")){
                    res = num1 * num2;
                }else if(item.equals("/")){
                    res = num1 / num2;
                    if (num2 == 0) {
                        throw new NumberFormatException("除数不能为0！");
                    }
                }else {
                    throw new RuntimeException("运算符错误！");
                }
                String rres = numberFormat.format(res);
                res = Double.parseDouble(rres);
                stack.push(res);
            }
        }
        if (stack.size() == 1){
            return Double.parseDouble(stack.pop().toString());
        } else{
            Double num = Double.parseDouble(stack.pop().toString());
            while (!stack.empty()){
                num = Math.sqrt(num);
                stack.pop();
            }
            return num;
        }
    }

    public static boolean isInt(double calculateResult){
        double n = calculateResult - (int)calculateResult;
        if(n!=0){
            return true;
        }else{
            return false;
        }
    }
}
